package nc.tb.pub.tree;

import java.util.Enumeration;
import java.util.NoSuchElementException;
import java.util.Vector;

import nc.tb.pub.IBusiObj;

public class TbTreeNodeObject {
	private IBusiObj vo;
	private TbTreeNodeObject parent;
	private Vector<TbTreeNodeObject> children;

	static public final Enumeration<TbTreeNodeObject> EMPTY_ENUMERATION
	= new Enumeration<TbTreeNodeObject>() {
		public boolean hasMoreElements() { return false; }
		public TbTreeNodeObject nextElement() {
			throw new NoSuchElementException("No more elements");
		}
	};
	final class BreadthFirstEnumeration implements Enumeration<TbTreeNodeObject> {
		protected Queue	queue;

		public BreadthFirstEnumeration(TbTreeNodeObject rootNode) {
			super();
			Vector<TbTreeNodeObject> v = new Vector<TbTreeNodeObject>(1);
			v.addElement(rootNode);	// PENDING: don't really need a vector
			queue = new Queue();
			queue.enqueue(v.elements());
		}

		public boolean hasMoreElements() {
			return (!queue.isEmpty() &&
					((Enumeration)queue.firstObject()).hasMoreElements());
		}

		public TbTreeNodeObject nextElement() {
			Enumeration	enumer = (Enumeration)queue.firstObject();
			TbTreeNodeObject	node = (TbTreeNodeObject)enumer.nextElement();
			Enumeration	children = node.children();

			if (!enumer.hasMoreElements()) {
				queue.dequeue();
			}
			if (children.hasMoreElements()) {
				queue.enqueue(children);
			}
			return node;
		}


		// A simple queue with a linked list data structure.
		final class Queue {
			QNode head;	// null if empty
			QNode tail;

			final class QNode {
				public Object	object;
				public QNode	next;	// null if end
				public QNode(Object object, QNode next) {
					this.object = object;
					this.next = next;
				}
			}

			public void enqueue(Object anObject) {
				if (head == null) {
					head = tail = new QNode(anObject, null);
				} else {
					tail.next = new QNode(anObject, null);
					tail = tail.next;
				}
			}

			public Object dequeue() {
				if (head == null) {
					throw new NoSuchElementException("No more elements");
				}

				Object retval = head.object;
				QNode oldHead = head;
				head = head.next;
				if (head == null) {
					tail = null;
				} else {
					oldHead.next = null;
				}
				return retval;
			}

			public Object firstObject() {
				if (head == null) {
					throw new NoSuchElementException("No more elements");
				}

				return head.object;
			}

			public boolean isEmpty() {
				return head == null;
			}
		}
	}

	public TbTreeNodeObject(IBusiObj obj) {
		vo = obj;
	}
	public int getChildCount() {
		return children==null ? 0 : children.size();
	}
	public TbTreeNodeObject getChildAt(int index) {
		if (children == null)
			return null;
		if (index >= 0 && index < children.size())
			return children.get(index);
		else
			return null;
	}
	public void removeChild(TbTreeNodeObject child) {
		if (children != null)
			children.remove(child);
	}
	public void removeChildeAt(int index) {
		if (children != null && index >= 0 && index < children.size())
			children.remove(index);
	}
	public void removeAllChildren() {
		if (children != null)
			children.clear();
	}
	public void addChild(TbTreeNodeObject child) {
		if (children == null)
			children = new Vector<TbTreeNodeObject>();
		children.add(child);
	}
	public void addChildAt(TbTreeNodeObject child, int index) {
		if (children == null)
			children = new Vector<TbTreeNodeObject>();
		if (index >= 0 && index <= children.size())
			children.add(index, child);
		else
			children.add(child);
	}
	public Enumeration children() {
		if (children == null) {
			return EMPTY_ENUMERATION;
		} else {
			return children.elements();
		}
	}
	public TbTreeNodeObject getParent() {
		return parent;
	}
	public void setParent(TbTreeNodeObject parent) {
		this.parent = parent;
	}
	public IBusiObj getVo() {
		return vo;
	}
	public void setVo(IBusiObj vo) {
		this.vo = vo;
	}

	public Enumeration breadthFirstEnumeration() {
		return new BreadthFirstEnumeration(this);
	}
}
